3

typeof 操作符(还有 instanceof)可能是 Javascript 设计中最大缺陷,因为它几乎是完全破损的。由于 typeof 用法与调用函数的语法相似,因此常被误以为是函数调用,实际上并不存在名为 typeof 的函数,typeof 只是一个操作符而已。
尽管 instanceof 仍然还有少数的应用场景,typeof 则只有一个实际的用途,但这个用途不能用来检测对象的类型。

类型表格

Value               Class      Type
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object (function in Nitro/V8)
new RegExp("meow")  RegExp     object (function in Nitro/V8)
{}                  Object     object
new Object()        Object     object

在上述表格中,Type 列表示 typeof 操作符的结果。而 Class 列则表示对象内部的 [[Class]] 属性。
为了获得 [[Class]] 属性,我们需要使用 Object.prototypetoString 方法。

Class 属性

文档中明确地给出了获得 [[Class]] 属性的途径,就是使用 Object.prototype.toString

function is(type, obj) {
    var clas = Object.prototype.toString.call(obj).slice(8, -1);
    return obj !== undefined && obj !== null && clas === type;
}

is('String', 'test'); // true
is('String', new String('test')); // true

上例中,Object.prototype.toString 被调用,this 被设置指向需要获取其 [[Class]] 属性值的对象。

文档定义: [[Class]] 属性的值只可能是下列字符串: Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String
nullundefined 调用 Object.prototype.toString 方法时, 其返回值将由 Object 变成了 NullUndefined

测试变量是否定义

typeof foo !== 'undefined'

上述语句将会测试变量 foo 已定义与否,如果未定义而引用 foo 将会抛出 ReferenceError 错误,这实际上是 typeof 用处最大的地方。

总结

为了检测一个对象的类型,最可靠的方法就是使用 Object.prototype.toString,正如第一个表格上的内容,typeof 操作符并不能返回确切的对象类型,但是我们可以使用 typeof 操作符经常会被用来判断变量是否定义。
其实 typeof 操作符还可以被用来测试变量是否为函数,@humphry 前辈的回答进一步丰富了 typeof 的用途:

《如何正确判断js数据类型》

参考

http://bonsaiden.github.io/JavaScript-Garden/#types.typeof


StephenLi
7k 声望488 粉丝

知不足。